﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CarolLib.Extension;
using DCS.Business.Interface;
using DCS.Business.Manager;
using DCS.Business.Model;
using DCS.DataProvider;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Collections;

namespace DCS.BusinessObject
{
    public class FIDSLDMSyncer : IMessageParser
    {
        static log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        static LDMMessageManager LDMmanager;

        static readonly System.IFormatProvider culture = new System.Globalization.CultureInfo("en-US", true);
        static readonly Regex rgFirstLine = new Regex("[0-9A-Z]{3,7}/[0-9]{2}[A-Z]{3}.");
        static readonly Regex rgPDate = new Regex("[0-9]{2}[A-Z]{3}[0-9]{2}");
        static readonly Regex rgRegNo = new Regex(@"\.B[0-9]{3,5}\.");
        static readonly Regex rgLayout = new Regex(@"[0-9A-Z]{2,20}\.[0-9]{2}/[0-9]{2}");
        //static readonly Regex rgFirstLine =new Regex(@"[0-9A-Z]{3,7}/[0-9]{2}[A-Z]{3}[0-9a-zA-z]+\.[0-9a-zA-z]+\.[0-9a-zA-z]+\.[0-9]{2}/[0-9]{2}");
        static readonly Regex rgLspHeader = new Regex(@"[0-9]{2}[A-Z]{3}[0-9]{2} [0-9]{4}");
        static readonly char[] dot = { '.' };
        static readonly char[] slash = { '/' };
        static readonly Regex rgLDMFlag = new Regex(@"([\s\S])+LDM([\s\S])+");

        //static readonly Regex rgLDMFlag = new Regex(@"[\s\S]+LDM[\s\S]+([a-zA-Z]{2}[\s\S]+)");

        public void Init()
        {
            IUnityContainer myContainer = new UnityContainer();
            UnityConfigurationSection section
              = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers["Data"].Configure(myContainer);

            IDataProvider dp = myContainer.Resolve<IDataProvider>();

            LDMmanager = new LDMMessageManager(dp);
        }

        public void DetectAndParse(int batchSize, string messageType)
        {
            //step 1. Get new LDM Msg
            List<FIDSLDMMsg> newMsgs = null;
            try
            {
                newMsgs = LDMmanager.GetNewLDMMsg(decimal.Parse(Properties.ParaSetting.Default.MaxLDMID));
            }
            catch (Exception ex)
            {
                Logger.Error("get new LDM MSG From DB error", ex);
            }

            if (newMsgs == null || newMsgs.Count == 0)
            {
                Logger.Info("there is no msg to parse");
                return;
            }

            Logger.InfoFormat("there is {0} msg to parse",newMsgs.Count);

            // parse
            List<LDMMessage> Results = new List<LDMMessage>();
            try
            {
                Results = Parse(newMsgs);
            }
            catch (Exception ex)
            {
                Logger.Error("Parse error", ex);
            }

            //save models

            try
            {
                LDMmanager.SaveDistinctEntities(Results.Distinct(new FlightInfoCompare()).ToList());

                string MaxID=newMsgs.Max(f=>f.TELEX_ID).ToString();
                Properties.ParaSetting.Default.MaxLDMID = MaxID;
                Properties.ParaSetting.Default.Save();

                Logger.InfoFormat("MaxID:{0}",MaxID);
            }
            catch (Exception ex)
            {
                Logger.Error("save ldmmessage error", ex);
            }
        }

        private List<LDMMessage> Parse(List<FIDSLDMMsg> Source)
        {
            List<LDMMessage> Results = new List<LDMMessage>();
            //step 2. get ldm content 
            foreach (FIDSLDMMsg ldmMsge in Source)
            {

                Match mm = rgLDMFlag.Match(ldmMsge.CONTEXT);

                string[] Contents = ldmMsge.CONTEXT.Split(new string[] { "LDM\r\n" }, StringSplitOptions.None);
                if (Contents.Length != 2)
                {
                    Logger.Info(string.Format("the content's LDM flag count is not only one, Telex_ID: {0}", ldmMsge.TELEX_ID));
                    continue;
                }

                StringReader reader = new StringReader(Contents[1]);

                List<LDMMessage> list = new List<LDMMessage>();

                #region  parse every line
                LDMMessage model = new LDMMessage();
                LDMMessage model2 = new LDMMessage();

                model.RefFileId = Convert.ToInt32(-1 * ldmMsge.TELEX_ID);
                model.PTime = ldmMsge.PTIME;
                string header = "";

                while ((header = reader.ReadLine()) != null)
                {
                    if (string.IsNullOrEmpty(header))
                    {
                        continue;
                    }

                    #region MU0517/07SEP10.B5475.C8Y162.02/07
                    if (rgFirstLine.IsMatch(header))
                    {
                        model.Carrier = header.Substring(0, 2);
                        model.FlightNo = header.Substring(2, header.IndexOf('/') - 2);
                        string pdate = rgPDate.Match(header).Value;
                        if (string.IsNullOrEmpty(pdate))
                        {
                            Logger.ErrorFormat("pdate formate error texlex_id : {0}", ldmMsge.TELEX_ID);
                            model.PDate = ldmMsge.PTIME.Date;
                        }
                        else
                        {
                            model.PDate = DateTime.ParseExact(pdate, "ddMMMyy", culture);
                        }
                        model.RegNo = rgRegNo.Match(header).Value.Replace(".", string.Empty);
                        string[] last = rgLayout.Match(header).Value.Split(dot);
                        model.Crew = last[1];
                        model.PaxLayout = last[0];
                    }
                    else
                    {
                        Logger.InfoFormat("there is no formate header ,telex_id: {0}", ldmMsge.TELEX_ID);
                        break;
                    }

                    #endregion

                    string text = reader.ReadLine();
                    if (text.StartsWith("-"))
                    {
                        try
                        {
                            FillMessageBody(model, reader, text);
                        }
                        catch (Exception ex1)
                        {
                            Logger.Error(string.Format("Fill MessageBody error,TELEX_ID:{0}", ldmMsge.TELEX_ID), ex1);
                            break;

                        }

                        list.Add(model);

                        text = reader.ReadLine();
                        if (text.StartsWith("-"))
                        {
                            model2 = model.Clone() as LDMMessage;

                            try
                            {
                                FillMessageBody(model2, reader, text);
                            }
                            catch (Exception ex2)
                            {
                                Logger.Error(string.Format("Fill MessageBody error,TELEX_ID:{0}", ldmMsge.TELEX_ID), ex2);
                                break;
                            }

                            list.Add(model2);
                            text = reader.ReadLine();

                        }

                        #region SI

                        text += reader.ReadToEnd();
                        list.ForEach(d => d.AdditionalInfo = text);

                        #endregion
                    }
                }

                #endregion

                if (list.Count > 0)
                {
                    try
                    {
                        if (GetDeptAirport(list))
                        {
                            Results.AddRange(list);
                        }
                        else
                        {
                            Logger.ErrorFormat("there is no deptairport telexid : {0} , FllightNo : {1}", ldmMsge.TELEX_ID,list[0].Carrier+list[0].FlightNo);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex);
                    }
                }
                else
                {
                    Logger.InfoFormat("the content parse no LDMMessage, telex_id: {0}", ldmMsge.TELEX_ID);
                }

            }
            return Results;
        }

        private void FillMessageBody(LDMMessage model, StringReader reader, string text)
        {
            #region -PVG.104/0/0.0.T673.2/673

            model.ArrAirport = text.Substring(1, 3);
            string[] block = text.Substring(5).Split(dot);

            string[] ps = block[0].Split(slash);
            if (ps.Length < 3 && text.EndsWith(".NIL"))
            {
                //NIL record.
                model.LoadInCompartment = string.Empty;
                return;
            }
            model.Adult = ps[0].TryToInt();
            model.Child = ps[1].TryToInt();
            model.Baby = ps[2].TryToInt();

            model.BagWeight = block[1].TryToInt();
            model.LoadTotal = block[2].Substring(1).TryToInt();

            int startLIC = text.IndexOf(block[2]) + block[2].Length + 1;
            if (startLIC < text.Length)
            {
                model.LoadInCompartment = text.Substring(text.IndexOf(block[2]) + block[2].Length + 1);
            }
            else
            {
                model.LoadInCompartment = string.Empty;
            }

            #endregion

            #region .PAX/2/102.PAD/0/0

            text = reader.ReadLine();
            if (!text.StartsWith(".PAX"))
            {
                model.LoadInCompartment += text;
                text = reader.ReadLine();
            }

            ps = text.Split(dot, StringSplitOptions.RemoveEmptyEntries);
            string[] paxs = ps[0].Replace("PAX", string.Empty).Split(slash, StringSplitOptions.RemoveEmptyEntries);
            string[] pads = ps[1].Replace("PAD", string.Empty).Split(slash, StringSplitOptions.RemoveEmptyEntries);

            if (model.PaxLayout == null)
            {
                model.PaxF = 0;
                model.PaxC = 0;
                model.PaxY = 0;
                model.PadF = 0;
                model.PadC = 0;
                model.PadY = 0;
            }
            else if ((paxs.Length == 1)
                && (model.PaxLayout.Contains('Y'))
                && !(model.PaxLayout.Contains('C'))
                && !(model.PaxLayout.Contains('F')))
            {
                model.PaxF = 0;
                model.PaxC = 0;
                model.PaxY = paxs[0].TryToInt();
                model.PadF = 0;
                model.PadC = 0;
                model.PadY = pads[0].TryToInt();
            }
            else if ((paxs.Length == 2)
                && (model.PaxLayout.Contains('Y'))
                && (model.PaxLayout.Contains('C'))
                && !(model.PaxLayout.Contains('F')))
            {
                model.PaxF = 0;
                model.PaxC = paxs[0].TryToInt();
                model.PaxY = paxs[1].TryToInt();
                model.PadF = 0;
                model.PadC = pads[0].TryToInt();
                model.PadY = pads[1].TryToInt();
            }
            else if ((paxs.Length == 2)
                && (model.PaxLayout.Contains('Y'))
                && !(model.PaxLayout.Contains('C'))
                && (model.PaxLayout.Contains('F')))
            {
                model.PaxF = paxs[0].TryToInt();
                model.PaxC = 0;
                model.PaxY = paxs[1].TryToInt();
                model.PadF = pads[0].TryToInt();
                model.PadC = 0;
                model.PadY = pads[1].TryToInt();
            }
            else
            {
                model.PaxF = paxs[0].TryToInt();
                model.PaxC = paxs[1].TryToInt();
                model.PaxY = paxs[2].TryToInt();
                model.PadF = pads[0].TryToInt();
                model.PadC = pads[1].TryToInt();
                model.PadY = pads[2].TryToInt();
            }

            #endregion
        }

        private bool GetDeptAirport(List<LDMMessage> Source)
        {

            List<FlightInfo> FlightInfos = LDMmanager.GetFlightInfoByPara(Source[0].PDate, Source[0].Carrier, Source[0].FlightNo);

            if (FlightInfos != null && FlightInfos.Count > 0)
            {
                foreach (LDMMessage model in Source)
                {
                    var item = FlightInfos.Find(f => f.ArrAirport == model.ArrAirport);
                    if (item != null)
                    {
                        model.DeptAirport = item.DeptAirport;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            else
            {
                return false;
            }
            return true;
        }
    }

    public class FlightInfoCompare : IEqualityComparer<LDMMessage>
    {
        public bool Equals(LDMMessage x, LDMMessage y)  
       {
           return ((x.PDate == y.PDate) && (x.Carrier == y.Carrier) && (x.FlightNo == y.FlightNo) &&
                      (x.DeptAirport == y.DeptAirport) && (x.ArrAirport == y.ArrAirport));
        }
        public int GetHashCode(LDMMessage obj) { return 0; }  
    }
}
